package com.by.rpc.provider;

import com.by.log.Logger;
import com.by.log.LoggerFactory;
import com.by.rpc.annotation.*;
import com.by.rpc.config.RpcProperties;
import com.by.rpc.dto.ServiceInstance;
import com.by.rpc.enums.ParameterPosition;
import com.by.rpc.registry.ServiceRegistry;
import com.by.rpc.util.KeyUtils;
import org.reflections.Reflections;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务提供者，负责扫描和注册RPC服务
 */
public class ServiceProvider implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(ServiceProvider.class);
    // 存储服务接口与实现类的映射关系: key=interfaceName+group+version, value=serviceImpl
    private final Map<String, Object> serviceMap;
    // 存储方法信息，用于RPC调用
    private final Map<String, MethodInfo> methodMap;
    private final String basePackage;
    private ServiceRegistry serviceRegistry;
    private ServiceInstance localServiceInstance;
    private ApplicationContext applicationContext;
    private RpcProperties rpcProperties;

    public ServiceProvider(RpcProperties rpcProperties) {
        this.basePackage = rpcProperties.getScanPackage();
        this.rpcProperties = rpcProperties;
        this.serviceMap = new ConcurrentHashMap<>();
        this.methodMap = new ConcurrentHashMap<>();
    }

    /**
     * 扫描并注册带有@RpcService和@ApiEndpoint注解的服务
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        // 如果之前没有初始化服务注册相关组件，则在此处初始化
        if (this.serviceRegistry == null) {
            initializeServiceRegistryIfNeeded();
        }
        scanAndRegisterServices();
    }

    /**
     * 初始化服务注册中心（如果需要）
     */
    private void initializeServiceRegistryIfNeeded() {
        try {
            if (applicationContext != null) {
                if (serviceRegistry == null) {
                    serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
                }
                if (rpcProperties == null) {
                    rpcProperties = applicationContext.getBean(RpcProperties.class);
                }
            }
        } catch (Exception e) {
            logger.warn("Failed to initialize service registry: {}", e.getMessage());
        }
    }

    /**
     * 扫描并注册带有@RpcService和@ApiEndpoint注解的服务
     */
    private void scanAndRegisterServices() {
        // 确保服务注册组件已初始化
        initializeServiceRegistryIfNeeded();
        Reflections reflections = new Reflections(basePackage);
        Set<Class<?>> serviceClasses = reflections.getTypesAnnotatedWith(RpcService.class);

        for (Class<?> clazz : serviceClasses) {
            try {
                // 获取注解信息
                RpcService rpcService = clazz.getAnnotation(RpcService.class);
                Class<?> interfaceClass = rpcService.interfaceClass();
                if (interfaceClass == void.class) {
                    // 如果没有指定接口类，则使用实现类直接实现的接口
                    Class<?>[] interfaces = clazz.getInterfaces();
                    if (interfaces.length > 0) {
                        interfaceClass = interfaces[0];
                    } else {
                        logger.warn("Service class {} does not implement any interface", clazz.getName());
                        continue;
                    }
                }

                String serviceName = interfaceClass.getName();
                String version = rpcService.version();
                String group = rpcService.group();

                // 创建服务实例
                Object serviceInstance;
                String beanName = getBeanName(clazz);
                if (applicationContext != null && applicationContext.containsBean(beanName)) {
                    serviceInstance = applicationContext.getBean(beanName);
                    logger.info("Using existing Spring bean for service: {}", clazz.getName());
                } else {
                    // 如果Spring容器中不存在，则通过反射创建新实例
                    serviceInstance = clazz.getDeclaredConstructor().newInstance();
                    logger.info("Created new instance for service: {}", clazz.getName());
                }

                // 构建服务唯一标识
                String serviceKey = KeyUtils.buildInnerCacheServiceKey(serviceName, version, group);
                serviceMap.put(serviceKey, serviceInstance);

                logger.info("Registered local service: {} with key: {}", clazz.getName(), serviceKey);

                // 如果有服务注册中心，则注册到注册中心
                if (serviceRegistry != null && rpcProperties != null) {
                    serviceRegistry.registerInterfaceToService(interfaceClass.getName(), rpcProperties.getServiceName(), 0);
                }

            } catch (Exception e) {
                logger.error("Failed to register service: {}", clazz.getName(), e);
            }
        }

        // 扫描带有@ApiEndpoint注解的Controller类
        Set<Class<?>> apiEndpointClasses = reflections.getTypesAnnotatedWith(ApiEndpoint.class);
        for (Class<?> clazz : apiEndpointClasses) {
            try {
                ApiEndpoint apiEndpoint = clazz.getAnnotation(ApiEndpoint.class);
                String serviceName = apiEndpoint.serviceName();
                if (serviceName == null || serviceName.isEmpty()) {
                    serviceName = clazz.getSimpleName();
                }

                String version = apiEndpoint.version();
                String group = apiEndpoint.group();

                // 为Controller类创建一个实例用于RPC调用
                Object controllerInstance;
                // 检查Spring容器中是否已存在该Bean
                String beanName = getBeanName(clazz);
                if (applicationContext != null && applicationContext.containsBean(beanName)) {
                    controllerInstance = applicationContext.getBean(beanName);
                    logger.info("Using existing Spring bean for API endpoint controller: {}", clazz.getName());
                } else {
                    // 如果Spring容器中不存在，则通过反射创建新实例
                    controllerInstance = clazz.getDeclaredConstructor().newInstance();
                    logger.info("Created new instance for API endpoint controller: {}", clazz.getName());
                }

                // 构建服务唯一标识
                String serviceKey = KeyUtils.buildInnerCacheServiceKey(serviceName, version, group);

                // 注意：如果已经有同名服务，不覆盖
                if (!serviceMap.containsKey(serviceKey)) {
                    serviceMap.put(serviceKey, controllerInstance);
                    logger.info("Registered API endpoint controller: {} with key: {}", clazz.getName(), serviceKey);
                }

                // 扫描带有@RpcMethod注解的方法
                scanAndRegisterApiEndpointMethods(clazz, serviceName, version, group, new StringBuilder());

                // 如果有服务注册中心，则注册到注册中心
                if (serviceRegistry != null && rpcProperties != null) {
                    // 注册服务实例到注册中心
                    ServiceInstance instance = new ServiceInstance();
                    instance.setServiceName(serviceName);
                    instance.setVersion(version);
                    instance.setGroup(group);
                    instance.setHost(rpcProperties.getServerHost());
                    instance.setPort(rpcProperties.getServerPort());
                    instance.setRegisterTime(System.currentTimeMillis());

                    serviceRegistry.register(instance);
                    logger.info("Registered API endpoint service instance {} to registry", instance);
                }
            } catch (Exception e) {
                logger.error("Failed to register API endpoint: {}", clazz.getName(), e);
            }
        }
    }

    /**
     * 获取Bean名称，基于Spring的命名规则
     *
     * @param clazz 类
     * @return Bean名称
     */
    private String getBeanName(Class<?> clazz) {
        // 检查是否有Spring的@Component注解（包括@Service, @Controller等）
        if (clazz.isAnnotationPresent(org.springframework.stereotype.Component.class)) {
            org.springframework.stereotype.Component component = clazz.getAnnotation(org.springframework.stereotype.Component.class);
            String value = component.value();
            if (!value.isEmpty()) {
                return value;
            }
        }

        // 检查@Service注解
        if (clazz.isAnnotationPresent(org.springframework.stereotype.Service.class)) {
            org.springframework.stereotype.Service service = clazz.getAnnotation(org.springframework.stereotype.Service.class);
            String value = service.value();
            if (!value.isEmpty()) {
                return value;
            }
        }

        // 检查@Controller注解
        if (clazz.isAnnotationPresent(org.springframework.stereotype.Controller.class)) {
            org.springframework.stereotype.Controller controller = clazz.getAnnotation(org.springframework.stereotype.Controller.class);
            String value = controller.value();
            if (!value.isEmpty()) {
                return value;
            }
        }

        // 使用默认命名规则：类名首字母小写
        String simpleName = clazz.getSimpleName();
        return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
    }

    /**
     * 扫描并注册带有@RpcMethod注解的方法（用于API端点）
     */
    private void scanAndRegisterApiEndpointMethods(Class<?> clazz, String serviceName, String version, String group, StringBuilder apiEndpointsInfo) {
        Method[] methods = clazz.getDeclaredMethods();

        for (Method method : methods) {
            if (method.isAnnotationPresent(RpcMethod.class)) {
                RpcMethod rpcMethod = method.getAnnotation(RpcMethod.class);
                String path = rpcMethod.value();
                String httpMethod = rpcMethod.method();
                Parameter[] parameters = method.getParameters();
                String fullPath = path.startsWith("/") ? path : ("/" + path);
                // 构建方法唯一标识
                String methodKey = KeyUtils.buildInnerCacheServiceKey(serviceName, version, group) + ":" + fullPath + ":" + httpMethod;
                methodMap.put(methodKey, new MethodInfo(method, clazz));
                logger.info("Registered RPC method: {} for service: {}", methodKey, serviceName);

                // 如果有服务注册中心，则将方法信息注册到注册中心
                if (serviceRegistry != null) {
                    // 构建方法注册键
                    String methodRegistryKey = KeyUtils.buildRpcEndpointMethodKey(serviceName, version, group, fullPath, httpMethod);

                    // 构建方法注册值（包含方法名和参数信息）
                    StringBuilder methodInfo = new StringBuilder();
                    methodInfo.append(method.getName()); // 方法名

                    // 添加参数信息
                    if (parameters.length > 0) {
                        methodInfo.append("|");
                        for (int i = 0; i < parameters.length; i++) {
                            if (i > 0) {
                                methodInfo.append(",");
                            }
                            Parameter param = parameters[i];
                            methodInfo.append(i).append(":")
                                    .append(param.getName()).append(":").append(param.getType().getName());
                            // 处理各种参数注解
                            if (param.isAnnotationPresent(RpcParam.class)) {
                                RpcParam rpcParam = param.getAnnotation(RpcParam.class);
                                String value = rpcParam.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.ANY);
                            } else if (param.isAnnotationPresent(RpcHeader.class)) {
                                RpcHeader rpcHeader = param.getAnnotation(RpcHeader.class);
                                String value = rpcHeader.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.HEADER);
                            } else if (param.isAnnotationPresent(RpcBody.class)) {
                                RpcBody rpcBody = param.getAnnotation(RpcBody.class);
                                String value = rpcBody.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.BODY);
                            } else if (param.isAnnotationPresent(RpcPath.class)) {
                                RpcPath rpcPath = param.getAnnotation(RpcPath.class);
                                String value = rpcPath.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.PATH);
                            } else if (param.isAnnotationPresent(RpcForm.class)) {
                                RpcForm rpcForm = param.getAnnotation(RpcForm.class);
                                String value = rpcForm.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.FORM);
                            } else if (param.isAnnotationPresent(RpcFile.class)) {
                                RpcFile rpcFile = param.getAnnotation(RpcFile.class);
                                String value = rpcFile.value();
                                methodInfo.append(":").append(value).append(":").append(ParameterPosition.FILE);
                            } else {
                                logger.warn("不支持的参数{}，请使用[RpcParam,RpcHeader,RpcBody,RpcPath,RpcForm,RpcFile]标记参数", param.getName());
                            }
                        }
                    }
                    // 注册到服务注册中心
                    serviceRegistry.registerApiEndpoint(methodRegistryKey, methodInfo.toString(), 0);
                }
            }
        }

        // 如果有服务注册中心，则将API端点信息注册到注册中心
        if (serviceRegistry != null && !apiEndpointsInfo.isEmpty()) {
            String registryKey = KeyUtils.buildRpcEndpointKey(serviceName, version, group);
            serviceRegistry.registerApiEndpoint(registryKey, apiEndpointsInfo.toString(), 0);
            logger.info("Registered API endpoints for service {} to registry: {}", serviceName, apiEndpointsInfo.toString());
        }
    }

    /**
     * 获取服务实例
     */
    public Object getLoadedService(String serviceName, String version, String group) {
        String serviceKey = KeyUtils.buildInnerCacheServiceKey(serviceName, version, group);
        return serviceMap.get(serviceKey);
    }

    /**
     * 获取方法信息
     */
    public MethodInfo getMethodInfo(String serviceName, String version, String group, String path, String httpMethod) {
        String methodKey = KeyUtils.buildInnerCacheServiceKey(serviceName, version, group) + ":" + path + ":" + httpMethod;
        return methodMap.get(methodKey);
    }

    // 内部类用于存储方法信息
    public static class MethodInfo {
        private final Method method;
        private final Class<?> clazz;

        public MethodInfo(Method method, Class<?> clazz) {
            this.method = method;
            this.clazz = clazz;
        }

        public Method getMethod() {
            return method;
        }

        public Class<?> getClazz() {
            return clazz;
        }
    }

    /**
     * 获取接口实现
     */
    public Object getLoadedInterface(String interfaceName, String version, String group) {
        String serviceKey = KeyUtils.buildInnerCacheServiceKey(interfaceName, version, group);
        return serviceMap.get(serviceKey);
    }

}